1. Overview
What You'll Learn
- How To Create A Key Pair
- How To Create A Registry in Omnicore
- How To Create A Device in Omnicore
- How To Connect An Omnicore Device With Mqtt Client
- How to Send Commands
3. Provision - Create A Key Pair
- Registry-level CA certificates are an optional feature for additional security; you are not required to use them. (Managing Credentials) If you are choosing to go without Registry-level CA certificates, then follow Option A below else follow Option B route.
Option A - Without Registry CA
- Create A Private Key With OpenSSl
#openssl genrsa -out private_key_filename bits openssl genrsa -out private.key 2048
- Create A Public Key With OpenSSl
#openssl rsa -in private_key_filename -outform PEM -pubout -out publickey_filename openssl rsa -in private.key -outform PEM -pubout -out public.pem
- The Private Key will be saved as private.key and the public key as public.pem
Option B - With Registry CA
- Create A Root CA And its Certificate
#openssl req -x509 -nodes -sha256 -days validity_certificate -newkey rsa:bits -keyout root_key_file -out root_certificate_file openssl req -x509 -nodes -sha256 -days 1825 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
- Create A Private Key With OpenSSl
#openssl genrsa -out private_key_filename bits
4. Provision - Create A Key Pair With RSA Algorithm
- Registry-level CA certificates are an optional feature for additional security; you are not required to use them. (Managing Credentials) If you are choosing to go without Registry-level CA certificates, then follow Option A below else follow Option B route.
Option A - Without Registry CA
- Create A Private Key With OpenSSl
#openssl genrsa -out private_key_filename bits openssl genrsa -out private.key 2048
- Create A Public Key With OpenSSl
#openssl rsa -in private_key_filename -outform PEM -pubout -out publickey_filename openssl rsa -in private.key -outform PEM -pubout -out public.pem
- The Private Key will be saved as private.key and the public key as public.pem
Option B - With Registry CA
- Create A Root CA And its Certificate
#openssl req -x509 -nodes -sha256 -days validity_certificate -newkey rsa:bits -keyout root_key_file -out root_certificate_file openssl req -x509 -nodes -sha256 -days 1825 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
- Create A Private Key With OpenSSl
#openssl genrsa -out private_key_filename bits openssl genrsa -out private.key 2048
- Create A Signing Request
#openssl req -key private_key_filename -new -out csr_filename openssl req -key private.key -new -out domain.csr
- Sign the Csr With Root CA
#openssl x509 -req -CA root_ca_cert_file -CAkey root_ca_key_file -in csr_filename -out device_cert_filename -days validitiy -CAcreateserial openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in domain.csr -out device.crt -days 365 -CAcreateserial
5. Provision - Create A Key Pair With EC Algorithm
- This Step can be skipped if you already have generated keys and certificates using RSA
- Registry-level CA certificates are an optional feature for additional security; you are not required to use them. (Managing Credentials) If you are choosing to go without Registry-level CA certificates, then follow Option A below else follow Option B route.
Option A - Without Registry CA
- Create A Private Key With OpenSSl
#openssl ecparam -genkey -name prime256v1 -noout -out file_name openssl ecparam -genkey -name prime256v1 -noout -out ec_private.key
- Create A Public Key With OpenSSl
#openssl ec -in private_key_filename -outform PEM -pubout -out publickey_filename openssl ec -in ec_private.key -pubout -outform PEM -pubout -out ec_public.pem
- The Private Key will be saved as ec_private.key and the public key as ec_public.pem
Option B - With Registry CA
- Create A Root CA And its Certificate
#openssl req -x509 -nodes -sha256 -days validity_certificate -newkey rsa:bits -keyout root_key_file -out root_certificate_file openssl req -x509 -nodes -sha256 -days 1825 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
- Create A Private Key With OpenSSl
#openssl ecparam -genkey -name prime256v1 -noout -out file_name openssl ecparam -genkey -name prime256v1 -noout -out ec_private.key
- Create A Signing Request
#openssl req -key private_key_filename -new -out csr_filename openssl req -key ec_private.key -new -out domain.csr
- Sign the Csr With Root CA
#openssl x509 -req -CA root_ca_cert_file -CAkey root_ca_key_file -in csr_filename -out device_cert_filename -days validitiy -CAcreateserial openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in domain.csr -out device.crt -days 365 -CAcreateserial
6. Provision - Create Sink (Optional)
- If you want your telemetry and state messages to be forwarded to Cloud Pub/Sub please configure a sink.Else skip this step.
- Go To Sink Tab And Click On Create Sink if not present.
- Copy Your Gcp Project Id To Project Field
- Follow the instructions and click continue.Choose either console or cli option.
7. Provision - Create A Registry
- Go To Registry Tab and click on New Registry
- If Root CA is needed, Paste the rootCA.crt generated in the previous step and paste it in the authentication.
- Enter Registry Details and Click Create. Sample Data is shown below.
8. Provision - Create A Device
- Go To Device Tab and click on New Device
- If Registry Has No CA ,Use the publickey.pem generated in previous step as authentication.If Registry Has Ca,specify the device.crt generated in previous step as authentication.Specify the key type also.
- Enter Device Details And Click On Create .
9. Connect - Generating JWT Token
- Generate A JWT Token From the private key generated as input.
C++
```C++
/**
* Calculates issued at / expiration times for JWT and places the time, as a
* Unix timestamp, in the strings passed to the function. The time_size
* parameter specifies the length of the string allocated for both iat and exp.
*/
static void GetIatExp(char* iat, char* exp, int time_size) {
// TODO(#72): Use time.google.com for iat
time_t now_seconds = time(NULL);
snprintf(iat, time_size, "%lu", now_seconds);
snprintf(exp, time_size, "%lu", now_seconds + 3600);
if (TRACE) {
printf("IAT: %s\n", iat);
printf("EXP: %s\n", exp);
}
}
static int GetAlgorithmFromString(const char* algorithm) {
if (strcmp(algorithm, "RS256") == 0) {
return JWT_ALG_RS256;
}
if (strcmp(algorithm, "ES256") == 0) {
return JWT_ALG_ES256;
}
return -1;
}
/**
* Calculates a JSON Web Token (JWT) given the path to a EC private key .
* Returns the JWT as a string that the caller must
* free.
*/
static char* CreateJwt(const char* ec_private_path,
const char* algorithm) {
char iat_time[sizeof(time_t) * 3 + 2];
char exp_time[sizeof(time_t) * 3 + 2];
uint8_t* key = NULL; // Stores the Base64 encoded certificate
size_t key_len = 0;
jwt_t* jwt = NULL;
int ret = 0;
char* out = NULL;
// Read private key from file
FILE* fp = fopen(ec_private_path, "r");
if (fp == NULL) {
printf("Could not open file: %s\n", ec_private_path);
return "";
}
fseek(fp, 0L, SEEK_END);
key_len = ftell(fp);
fseek(fp, 0L, SEEK_SET);
key = malloc(sizeof(uint8_t) * (key_len + 1)); // certificate length + \0
fread(key, 1, key_len, fp);
key[key_len] = '\0';
fclose(fp);
// Get JWT parts
GetIatExp(iat_time, exp_time, sizeof(iat_time));
jwt_new(&jwt);
// Write JWT
ret = jwt_add_grant(jwt, "iat", iat_time);
if (ret) {
printf("Error setting issue timestamp: %d\n", ret);
}
ret = jwt_add_grant(jwt, "exp", exp_time);
if (ret) {
printf("Error setting expiration: %d\n", ret);
}
ret = jwt_set_alg(jwt, GetAlgorithmFromString(algorithm), key, key_len);
if (ret) {
printf("Error during set alg: %d\n", ret);
}
out = jwt_encode_str(jwt);
if (!out) {
perror("Error during token creation:");
}
// Print JWT
if (TRACE) {
printf("JWT: [%s]\n", out);
}
jwt_free(jwt);
free(key);
return out;
}
```
Java
```Java
static MqttCallback mCallback;
static long MINUTES_PER_HOUR = 60;
/** Create a Omnicore JWT signed with the given RSA key. */
private static String createJwtRsa( String privateKeyFile)
throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
DateTime now = new DateTime();
// Create a JWT to authenticate this device. The device will be disconnected after the token
// expires, and will have to reconnect with a new token.
JwtBuilder jwtBuilder =
Jwts.builder()
.setIssuedAt(now.toDate())
.setExpiration(now.plusMinutes(20).toDate())
byte[] keyBytes = Files.readAllBytes(Paths.get(privateKeyFile));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return jwtBuilder.signWith(SignatureAlgorithm.RS256, kf.generatePrivate(spec)).compact();
}
```
Golang
```Golang
import (
"errors"
"io/ioutil"
"time"
jwt "github.com/golang-jwt/jwt"
)
// createJWT creates a Omnicore JWT for the given subscription id.
// algorithm can be one of ["RS256", "ES256"].
func createJWT( privateKeyPath string, algorithm string, expiration time.Duration) (string, error) {
claims := jwt.StandardClaims{
IssuedAt: time.Now().Unix(),
ExpiresAt: time.Now().Add(expiration).Unix(),
}
keyBytes, err := ioutil.ReadFile(privateKeyPath)
if err != nil {
return "", err
}
token := jwt.NewWithClaims(jwt.GetSigningMethod(algorithm), claims)
switch algorithm {
case "RS256":
privKey, _ := jwt.ParseRSAPrivateKeyFromPEM(keyBytes)
return token.SignedString(privKey)
case "ES256":
privKey, _ := jwt.ParseECPrivateKeyFromPEM(keyBytes)
return token.SignedString(privKey)
}
return "", errors.New("Cannot find JWT algorithm. Specify 'ES256' or 'RS256'")
}
```
Nodejs
```Nodejs
const createJwt = ( privateKeyFile, algorithm) => {
// Create a JWT to authenticate this device. The device will be disconnected
// after the token expires, and will have to reconnect with a new token. The
const token = {
iat: parseInt(Date.now() / 1000),
exp: parseInt(Date.now() / 1000) + 20 * 60, // 20 minutes
};
const privateKey = readFileSync(privateKeyFile);
return jwt.sign(token, privateKey, {algorithm: algorithm});
};
```
Python
```python
def create_jwt( private_key_file, algorithm):
"""Creates a JWT (https://jwt.io) to establish an MQTT connection.
Args:
private_key_file: A path to a file containing either an RSA256 or
ES256 private key.
algorithm: The encryption algorithm to use. Either 'RS256' or 'ES256'
Returns:
A JWT generated from the given private key, which
expires in 20 minutes. After 20 minutes, your client will be
disconnected, and a new JWT will have to be generated.
Raises:
ValueError: If the private_key_file does not contain a known key.
"""
token = {
# The time that the token was issued at
"iat": datetime.datetime.now(tz=datetime.timezone.utc),
# The time the token expires.
"exp": datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(minutes=20),
}
# Read the private key file.
with open(private_key_file, "r") as f:
private_key = f.read()
print(
"Creating JWT using {} from private key file {}".format(
algorithm, private_key_file
)
)
return jwt.encode(token, private_key, algorithm=algorithm)
```
10. Connect - Connecting With Mqtt Client
- Open the device details tab from the right side.
- Copy the Details Onto The Mqtt Client.Shown below is the MQTT X mqtt client. You can use any MQTT client of your choice. Paste the token generated in the previous step as the mqtt password field in the client.
- Click On Connect.
11. Manage - Publishing Command Data To Device
- Once Connected ,Get the Mqtt Topic information from device details tab.
- Open The Subscription Tab And Subscribe for the Command topic.
- Publish Command Data From The Console.
12. Manage - Fetching Published Data From Mqtt Client
- View the messages from the subscribed topic.
- Messages are base64 encoded.